package com.ruoyi.durian.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.DurianRedisKeysType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.RedisGeoUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.durian.domain.LlMap;
import com.ruoyi.durian.domain.LlSearchHistory;
import com.ruoyi.durian.mapper.LlSearchHistoryMapper;
import com.ruoyi.durian.service.LlMapService;
import com.ruoyi.durian.mapper.LlMapMapper;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author lenovo
 * @description 针对表【ll_map(地图模块-地图表)】的数据库操作Service实现
 * @createDate 2024-07-26 16:17:15
 */
@Service
public class LlMapServiceImpl extends ServiceImpl<LlMapMapper, LlMap>
        implements LlMapService {

    @Resource
    private LlMapMapper llMapMapper;

    @Resource
    private RedisGeoUtils redisGeoUtils;

    @Resource
    private LlSearchHistoryMapper llSearchHistoryMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 初始化地图
     *
     * @return
     */
    @Override
    public AjaxResult initMap() {
        List<LlMap> mapList = llMapMapper.selectList(null);
        LinkedHashMap<String, Point> initMap = new LinkedHashMap<>();
        mapList.forEach(item -> {
            Map<String, String> map = new LinkedHashMap<>();
            map.put("id", item.getId().toString());
            map.put("address", item.getName());
            map.put("addressInfo", item.getAddress());
            String key = JSONObject.toJSONString(map);
            initMap.put(key, new Point(Double.parseDouble(item.getMapX()), Double.parseDouble(item.getMapY())));
        });
        redisGeoUtils.geoAdd(DurianRedisKeysType.ADDRESS.getKey(), initMap);
        return AjaxResult.success();
    }

    /**
     * 查询半径内的地点
     *
     * @param range 半径
     * @param mapX  当前位置的横坐标
     * @param mapY  当前位置的纵坐标
     * @return
     */
    @Override
    public AjaxResult selectRadiusByAddress(Integer range, String mapX, String mapY) {
        GeoResults city = redisGeoUtils.radiusByxy(mapX, mapY, DurianRedisKeysType.ADDRESS.getKey(), range, 50 * range);
        return AjaxResult.success(city);
    }

    /**
     * 计算预计到达
     *
     * @param startAddressId 开始地点
     * @param endAddressId   结束地点
     * @return
     */
    @Override
    @Transactional
    public Map<String, Object> howOver(Integer startAddressId, Integer endAddressId) {

        Integer userId = 1204;

        LlMap start = llMapMapper.selectById(startAddressId);
        LlMap end = llMapMapper.selectById(endAddressId);

        if (start == null || end == null) {
            throw new ServiceException("地点错误");
        }

        LlSearchHistory history = new LlSearchHistory();
        history.setUserId(userId);
        history.setAddress(end.getName());
        history.setAllAddress(end.getAddress());
        history.setCreateTime(new Date());
        history.setUpdateTime(new Date());
        history.setMapId(end.getId());
        history.setIsDelete(0);

        llSearchHistoryMapper.insert(history);

        LinkedHashMap<String, String> startMap = new LinkedHashMap<>();
        startMap.put("id", start.getId().toString());
        startMap.put("address", start.getName().toString());
        startMap.put("addressInfo", start.getAddress().toString());

        String startJson = JSONObject.toJSONString(startMap);

        LinkedHashMap<String, String> endMap = new LinkedHashMap<>();
        endMap.put("id", end.getId().toString());
        endMap.put("address", end.getName().toString());
        endMap.put("addressInfo", end.getAddress().toString());

        String endJson = JSONObject.toJSONString(endMap);
        //计算两点之间的直线距离
        Distance distance = redisGeoUtils.distance(DurianRedisKeysType.ADDRESS.getKey(),startJson, endJson);

        /*
         * 一辆车正常车速是 40km/h
         * 40 / 60m = 0.67km/m
         * 也就是一分钟走0.67km
         * 所以使用计算的直线距离乘以0.67
         */

        BigDecimal time = BigDecimal.valueOf(distance.getValue())
                .divide(new BigDecimal("0.01"))
                .setScale(0, RoundingMode.CEILING);
        //初始化返回值
        LinkedHashMap<String, Object> resultMap = new LinkedHashMap<>();
        //当前时间往后推需要到达的时间
        LocalDateTime currentTime = LocalDateTime.now();
        LocalDateTime advancedTime = LocalDateTime
                .from(currentTime.plus(Duration.ofSeconds(Long.valueOf(time.toString()))));
        DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        resultMap.put("advancedTime", advancedTime.format(pattern));
        resultMap.put("rang", distance);
        return resultMap;
    }

    /**
     * 检索地点
     *
     * @param keyWord
     * @return
     */
    @Override
    public List<LlMap> searchAddress(String keyWord) {
        if (!StringUtils.isNotEmpty(keyWord)) {
            throw new ServiceException("请输入检索地点");
        }
        return llMapMapper.selectList(new QueryWrapper<LlMap>().like("name", keyWord));
    }

    /**
     * 搜索地图的详情
     * @param id
     * @return
     */
    @Override
    public AjaxResult search(Integer id) {
        Integer userId=619;
        //从redis中获取50条记录
//        Set<String> range = stringRedisTemplate.opsForZSet().range("searchHistory:" + userId, 0, 50);
//        if (range!=null && range.size()>0){
//            range.forEach(s -> {
//                LlSearchHistory history = JSONObject.parseObject(s, LlSearchHistory.class);
//                if (history.getMapId().equals(id)){
//                    stringRedisTemplate.opsForZSet().add("searchHistory:"+userId,s,);
//                }
//            });
//        }



        LlMap map =getById(id);
        LlSearchHistory history = new LlSearchHistory();
        history.setMapId(id);
        history.setIsDelete(0);
        history.setAddress(map.getName());
        history.setAllAddress(map.getAddress());
        history.setUserId(userId);
        history.setCreateTime(new Date());
        history.setUpdateTime(new Date());

        LambdaQueryWrapper<LlSearchHistory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LlSearchHistory::getMapId,id)
                .eq(LlSearchHistory::getUserId,userId);
        LlSearchHistory one = llSearchHistoryMapper.selectOne(wrapper);

        if (one!=null){
            LinkedHashMap<String, Object> hashMap = new LinkedHashMap<>();
            hashMap.put("userId", userId);
            hashMap.put("mapId", id);
            hashMap.put("address", one.getAddress());
            hashMap.put("allAddress",one.getAllAddress());
            String s1 = JSONObject.toJSONString(hashMap);
            Double score = stringRedisTemplate.opsForZSet().incrementScore("searchHistory:" + userId, s1, 0);
            stringRedisTemplate.opsForZSet().add("searchHistory:"+userId,s1,score+1);
            return AjaxResult.success(map);
        }
        llSearchHistoryMapper.insert(history);
        LinkedHashMap<String, Object> hashMap = new LinkedHashMap<>();
        hashMap.put("userId", userId);
        hashMap.put("mapId", id);
        hashMap.put("address", history.getAddress());
        hashMap.put("allAddress",history.getAllAddress());
        String s = JSONObject.toJSONString(hashMap);
        stringRedisTemplate.opsForZSet().add("searchHistory:"+userId,s,1);

        return AjaxResult.success(map);

    }

}




